/**
 * @file Error.hpp
 *
 * @date 15/11/2011
 * @author Tales
 */

#ifndef _YEP_ERROR_HPP_
#define _YEP_ERROR_HPP_

#include <sstream>

namespace yep
{
    using namespace std;
    /**
     * @brief An exception.
     *
     * All yep's exceptions thrown by this library uses this class. You shouldn't use
     *  the constructor diArealy, but use the @ref YEP_ERROR instead.
     */
    class Error
    {
    public:
        /**
         * @brief Constructs the Error. Prefer using the YEP_ERROR() macro instead.
         **/
        Error( const string& reason_, const char* file, int line ):_reason(reason_)
        {
            _file = file;
            _line = line;
        }

        /**
         * @brief Gets the _reason for the error
         **/
        const string &reason() const
        {
            return _reason;
        }

        /**
         * @brief Gets the file from source code where the error occured
         **/
        const char *file() const
        {
            return _file;
        }

        /**
         * @brief Gets the line from source code where the error ocurred
         **/
        int line() const
        {
            return _line;
        }

        /**
         * @brief Gets the erro explanation
         **/
        string explain() const
        {
            stringstream stream;
            stream << "Error '" << _reason << "' from file '" << _file << "' on line '" << _line << "'";
            return stream.str();
        }
    private:
        string _reason;
        const char *_file;
        int _line;
    };
}

/**@def YEP_ERROR
 * @brief Throw an error, automatically collecting this location.
 */
#define YEP_ERROR(REASON) throw Error((REASON), __FILE__, __LINE__)

/**@def YEP_ASSERT
 * @brief Do an assertion
 */
#ifndef YEP_IS_RELEASE // On debug build

#define YEP_ASSERT(x) ((x)?(void)0:(YEP_ERROR("Assertion invalid: "#x)) )

#else // On release build

#define YEP_ASSERT(x) ((void)0)

#endif
/**@brief YEP_ERROR_TEST
 * @brief Tests an condition. If it fails throw an error, automatically collecting this location.
 */
#define YEP_ERROR_TEST(x, REASON) ((x)?(void)0:(YEP_ERROR(REASON) ))


#endif /* _YEP_ERROR_HPP_ */
